package ldh.im.fxbase.dao;

import ldh.im.fxbase.data.pojo.ImGroup;
import ldh.im.fxbase.data.pojo.ImGroupUser;
import ldh.im.fxbase.data.pojo.ext.ImGroupExt;
import ldh.im.fxbase.util.DbUtil;
import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.dbutils.handlers.ArrayListHandler;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class ImGroupDao extends BaseDao {

    private static final String TABLE_NAME = "im_group";
    private static final String GROUP_COLUMNS = "g.id, g.name, g.currentUserId, g.code, g.serverId, g.ownerId, g.groupType groupTypeValue, g.status statusValue, g.description, g.version, " +
            "g.firstLetter, g.createTime, g.updateTime";

    private ImGroupUserDao imGroupUserDao = new ImGroupUserDao();

    public List<ImGroup> getNewGroups(String userId, int size) throws SQLException {
        return DbUtil.transaction((queryRunner, connection) -> {
            String sql = String.format("select %s from im_group g, im_group_user gu where g.id = gu.groupId and g.currentUserId = ? and gu.userId=? order by updateTime desc " +
                    "limit 0, %s", GROUP_COLUMNS, size);
            List<ImGroupExt> imGroupList = queryRunner.query(connection, sql, new BeanListHandler<>(ImGroupExt.class), userId, userId);
            for(ImGroupExt imGroup : imGroupList) {
                imGroup.setGroupUserSet(imGroupUserDao.getGroupUsersByGroupId(imGroup.getId()));
            }
            return imGroupList.stream().map(g->g).collect(Collectors.toList());
        });
    }

    public void insertImGroup(ImGroup imGroup) throws SQLException {
        DbUtil.transaction((queryRunner, connection) -> {
            ResultSetHandler<Long> h = new ScalarHandler();
            String sql = String.format("insert into im_group(name, currentUserId, serverId, code, ownerId, groupType, status, firstLetter, description, version, createTime, updateTime) " +
                    "values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
            long n = queryRunner.insert(connection, sql, h, imGroup.getName(), imGroup.getCurrentUserId(), imGroup.getServerId(), imGroup.getCode(), imGroup.getOwnerId(),
                    valueEnum(imGroup.getGroupType()), valueEnum(imGroup.getStatus()), imGroup.getFirstLetter(), imGroup.getDescription(), imGroup.getVersion(), imGroup.getCreateTime(),
                    imGroup.getUpdateTime());
            imGroup.setId(n);

            imGroupUserDao.batchInserts(imGroup);
            return n;
        });
    }

    public void batchInserts(List<ImGroup> imGroupList) throws SQLException {
        if (imGroupList.size() < 1) return;
        DbUtil.transaction((queryRunner, connection) -> {
            Object[][] paras = imGroupList.stream().map(imGroup->new Object[]{imGroup.getServerId(), imGroup.getCode(), imGroup.getCurrentUserId(), imGroup.getName(), imGroup.getOwnerId(),
                    valueEnum(imGroup.getGroupType()), valueEnum(imGroup.getStatus()), imGroup.getFirstLetter(), imGroup.getDescription(), imGroup.getCreateTime(), imGroup.getUpdateTime()}).toArray(Object[][]::new);
            String sql = String.format("insert into im_group(serverId, code, currentUserId, name, ownerId, groupType, status, firstLetter, description, createTime, updateTime) " +
                    "values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
            List<Object[]> results = queryRunner.insertBatch(connection, sql, new ArrayListHandler(), paras);

            for(int i=0; i<results.size(); i++) {
                Long bigInteger = (Long) results.get(i)[0];
                imGroupList.get(i).setId(bigInteger.longValue());
            }
            for(ImGroup imGroup : imGroupList) {
                imGroupUserDao.batchInserts(imGroup);
            }
            return imGroupList;
        });
    }

    public void batchUpdates(Set<ImGroup> imGroupList) throws SQLException {
        if (imGroupList.size() < 1) return;
        DbUtil.transaction((queryRunner, connection) -> {
            Object[][] paras = imGroupList.stream().map(imGroup->new Object[]{imGroup.getServerId(), imGroup.getCode(), imGroup.getName(), imGroup.getDescription(), imGroup.getOwnerId(),
                    valueEnum(imGroup.getStatus()), imGroup.getFirstLetter(), imGroup.getUpdateTime(), imGroup.getId()}).toArray(Object[][]::new);
            String sql = String.format("update im_group set serverId = ?, code = ?, name = ?, description = ?, ownerId = ?, status = ?, firstLetter = ?, version = version + 1, updateTime = ? " +
                    "where id = ?");

            int[] n = queryRunner.batch(connection, sql, paras);
            if (n.length != imGroupList.size()) {
                throw new RuntimeException("更新im_group失败， n =" + n);
            }

            return imGroupList;
        });
    }

    public void update(ImGroup imGroup) throws SQLException {
        DbUtil.transaction((queryRunner, connection) -> {
            Byte status = valueEnum(imGroup.getStatus());
            String sql = String.format("update im_group set serverId = ?, name = ?, description = ?, ownerId = ?,  " +
                    "status = ?, firstLetter = ?, version = version + 1, updateTime = ? where id = ?");
            long n = queryRunner.update(connection, sql, imGroup.getServerId(), imGroup.getName(), imGroup.getDescription(), imGroup.getOwnerId(),
                    status, imGroup.getFirstLetter(), imGroup.getUpdateTime(), imGroup.getId());
            if (n != 1) {
                throw new RuntimeException("更新数据失败");
            }
            imGroupUserDao.deleteGroupUsers(imGroup);
            imGroupUserDao.batchInserts(imGroup);
            return n;
        });
    }

    public void updateNameAndDescription(ImGroup imGroup) throws SQLException {
        DbUtil.transaction((queryRunner, connection) -> {
            String sql = String.format("update im_group set name = ?, description = ?, version = version + 1, updateTime = ? where id = ?");
            long n = queryRunner.update(connection, sql, imGroup.getName(), imGroup.getDescription(), imGroup.getUpdateTime(), imGroup.getId());
            if (n != 1) {
                throw new RuntimeException("更新数据失败");
            }
            return n;
        });
    }

    public void updateServerId(ImGroup imGroup) throws SQLException {
        DbUtil.transaction((queryRunner, connection) -> {
            Byte status = valueEnum(imGroup.getStatus());
            String sql = String.format("update im_group set serverId = ?, status = ?, version = version + 1, updateTime = ? where id = ?");
            long n = queryRunner.update(connection, sql, imGroup.getServerId(), status, imGroup.getUpdateTime(), imGroup.getId());
            if (n != 1) {
                throw new RuntimeException("更新数据失败");
            }
            return n;
        });
    }

    public ImGroup addUsersToImGroup(ImGroup imGroup) throws SQLException {
        return DbUtil.transaction((queryRunner, connection) -> {
            imGroupUserDao.batchInserts(imGroup);
            Set<ImGroupUser> groupUsers = imGroupUserDao.getGroupUsersByGroupId(imGroup.getId());
            imGroup.setGroupUserSet(groupUsers);
            ImGroupUser groupUser = groupUsers.stream().filter(gu->gu.getUserId().equals(imGroup.getCurrentUserId())).findFirst().get();
            imGroup.setCurrentGroupUser(groupUser);
            return imGroup;
        });
    }

    public ImGroup getByUserIdAndId(String userId, Long id) throws SQLException {
        return DbUtil.transaction((queryRunner, connection) -> {
            String sql = String.format("select %s from im_group g where g.currentUserId = ? and g.id = ?", GROUP_COLUMNS);
            ImGroupExt t = queryRunner.query(connection, sql, new BeanHandler<>(ImGroupExt.class), userId, id);
            setGroupUser(t);
            return t;
        });
    }

    public ImGroup getByCodeAndUserId(String code, String userId) throws SQLException {
        return DbUtil.transaction((queryRunner, connection) -> {
            String sql = String.format("select %s from im_group g where g.currentUserId = ? and g.code = ?", GROUP_COLUMNS);
            ImGroupExt t = queryRunner.query(connection, sql, new BeanHandler<>(ImGroupExt.class), userId, code);
            setGroupUser(t);
            return t;
        });
    }

    public ImGroup getByUserIdAndId(String userId, String serverId) throws SQLException {
        return DbUtil.transaction((queryRunner, connection) -> {
            String sql = String.format("select %s from im_group g where g.currentUserId = ? and (g.serverId = ? or g.code = ?)", GROUP_COLUMNS);
            ImGroupExt t = queryRunner.query(connection, sql, new BeanHandler<>(ImGroupExt.class), userId, serverId, serverId);
            setGroupUser(t);
            return t;
        });
    }

    public List<ImGroup> getImGroupByCodes(String userId, Set<String> codes) throws SQLException {
        if (codes.size() < 1) return new ArrayList<>();
        String codeParam = codes.stream().map(code-> String.format("\'%s\'", code)).collect(Collectors.joining(","));
        return DbUtil.transaction((queryRunner, connection) -> {
            String sql = String.format("select %s from im_group g where g.currentUserId = ? and g.code in (%s)", GROUP_COLUMNS, codeParam);
            List<ImGroupExt> groupExts = queryRunner.query(connection, sql, new BeanListHandler<>(ImGroupExt.class), userId);
            for (ImGroupExt groupExt : groupExts) {
                setGroupUser(groupExt);
            }
            return groupExts.stream().map(ge->ge).collect(Collectors.toList());
        });
    }

    public List<ImGroup> getNeedSendGroupsByUserId(String userId, int pageSize) throws SQLException {
        return DbUtil.transaction((queryRunner, connection) -> {
            String sql = String.format("select %s from im_group g where g.currentUserId = ? and (g.serverId is null or g.status = '-1') limit 0, %s", GROUP_COLUMNS, pageSize);
            List<ImGroupExt> groupExts = queryRunner.query(connection, sql, new BeanListHandler<>(ImGroupExt.class), userId);
            for (ImGroupExt groupExt : groupExts) {
                setGroupUser(groupExt);
            }
            return groupExts.stream().map(ge->ge).collect(Collectors.toList());
        });
    }

    public List<ImGroup> getDefaultGroups(String userId) throws SQLException {
        return getNewGroups(userId, 100);
    }

    private void setGroupUser(ImGroup group) throws SQLException {
        if (group != null) {
            group.setGroupUserSet(imGroupUserDao.getGroupUsersByGroupId(group.getId()));
            ImGroupUser groupUser = group.getGroupUserSet().stream().filter(gu->gu.getUserId().equals(group.getCurrentUserId())).findFirst().get();
            group.setCurrentGroupUser(groupUser);
        }
    }
}
